package org.gnomus.server;

import com.google.appengine.api.memcache.MemcacheServiceFactory;
import com.google.appengine.api.memcache.StrictErrorHandler;
import org.gnomus.server.controllers.Access;
import org.gnomus.util.*;

import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Interceptor extends javax.servlet.http.HttpServlet {

    static {
        // http://groups.google.com/group/google-appengine/msg/cb538fa9b024f362
        Interceptor.class.getClassLoader().setDefaultAssertionStatus(true);
        // http://code.google.com/appengine/docs/java/howto/maintenance.html
        MemcacheServiceFactory.getMemcacheService().setErrorHandler(new StrictErrorHandler());
    }

    protected void service(HttpServletRequest req, HttpServletResponse res) {
        stdio.startCapture();
        misc.checkAssertions();
        if (C.PRODUCTION) {
            try {
                _service(req, res);
                stdio.flush();
            } catch (Throwable t) {
                handleException(req, res, t);
            }
        } else {
            time.trace("Interceptor._service");
            _service(req, res);
            time.trace("Interceptor._service");
            stdio.flush();
        }
    }

    private void _service(HttpServletRequest req, HttpServletResponse res) {
        String uri = extractUri(req, res);
        if (uri.startsWith("/_ah/")) {
            try {
                res.setStatus(HttpServletResponse.SC_OK);
//                req.getRequestDispatcher("/WEB-INF/layout/page.jsp").include(req, res);
                return;
            } catch (Throwable t) {
                throw new Error(t);
            }
        }
        if (!C.PRODUCTION) {
            System.err.println("Interceptor._service: uri = " + uri);
        }
        Context ctx = Context.create(this, req, res, uri);
        System.err.println("Interceptor._service: ctx = " + ctx.toString());
        res.setContentType("text/html");
        res.setStatus(HttpServletResponse.SC_OK);
        if (Dispatcher.dispatch()) {
            if (ctx.cookie.isDirty()) {
                ctx.res.addCookie(ctx.cookie.getCookie());
            }
            Access.enqueue(HttpServletResponse.SC_OK);
        } else {
            ctx.view = "/".equals(ctx.uri) ? "index" : "not found";
            RequestDispatcher rd = ctx.req.getRequestDispatcher("/WEB-INF/layout/page.jsp");
            try {
                rd.include(ctx.req, ctx.res);
            } catch (Throwable t) {
                throw new Error(t);
            }
        }
    }

    private String extractUri(HttpServletRequest req, HttpServletResponse res) {
        if (!isSC(res, HttpServletResponse.SC_FORBIDDEN) && !isSC(res, HttpServletResponse.SC_NOT_FOUND)) {
            return req.getRequestURI();
        } else {
            String u = null;
            String h = null;
            String[] r = req.toString().split("\\n");
            for (String s : r) {
                s = s.trim();
                if ((s.startsWith("GET") || s.startsWith("POST") || s.startsWith("HEAD")) && s.endsWith("HTTP/1.1")) {
                    String[] t = s.split("\\s");
                    if (t.length > 2) {
                        u = t[1].trim();
                    }
                } else if (s.startsWith("Host: ")) {
                    h = s.substring(6).trim();
                }
            }
            String prefix = "http://" + h + "/";
            if (u != null && h!= null && u.startsWith(prefix)) {
                u = u.substring(prefix.length() - 1);
            }
            if (strings.isEmpty(u) || "/index.html".equals(u)) {
                u = "/";
            }
            int ix = u.indexOf('?');
            if (ix > 0) {
                u = u.substring(0, ix);
            }
            return u;
        }
    }

    private boolean isSC(HttpServletResponse res, int sc) {
        String[] r = res.toString().split(" ");
        return r.length > 1 && strings.a2i(r[1].trim(), -1) == sc;
    }

    private void handleException(HttpServletRequest req, HttpServletResponse res, Throwable t) {
        String u = extractUri(req, res);
        if (u != null && u.contains("reportException")) {
            t = misc.unwind(t);
            System.err.println("ERROR: nested exception in \"reportException\"" + t.getMessage());
            t.printStackTrace();
            return;
        }
        String io = stdio.getCaptureContent();
        Context ctx = Context.get();
        String cs = ctx != null ? ctx.toString() : "ctx=null";
    }
}
